Skip to content

gglessner/CommonsText-Scanner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Apache Commons Text Anti-Pattern Scanner

A static analysis tool for detecting code patterns that make Java applications vulnerable to CVE-2022-42889 (Text4Shell) and CVE-2025-46295 - Remote Code Execution vulnerabilities in Apache Commons Text.

Vulnerability Overview

Apache Commons Text versions 1.5 through 1.9 contain a critical vulnerability in the string interpolation feature. The StringSubstitutor class, when configured with default interpolators, enables dangerous lookups that can be exploited for:

  • Remote Code Execution via ${script:javascript:...} payloads
  • Server-Side Request Forgery (SSRF) via ${url:...} payloads
  • DNS Exfiltration via ${dns:...} payloads
CVE CVSS Score Affected Versions Fixed Version
CVE-2022-42889 9.8 (Critical) 1.5 - 1.9 1.10.0+
CVE-2025-46295 Critical 1.5 - 1.9 1.10.0+

Exploitation Requirements

For successful exploitation, all four vectors must be present:

Vector Description Example
1 Vulnerable Dependency commons-text:1.9 in pom.xml
2 Dangerous Interpolator StringSubstitutor.createInterpolator()
3 Untrusted Input User input passed to replace()
4 No Input Sanitization Missing ${...} pattern filtering

Installation

No installation required. The scanner is a standalone Python 3 script with no external dependencies.

# Clone or download
git clone <repository-url>
cd commons-text-scanner

# Verify Python 3 is available
python --version  # or python3 --version

Usage

Basic Scan

python commons_text_antipattern_scanner.py /path/to/java/project

Command Line Options

Option Description
directory Directory to scan (required)
-f, --format Output format: text (default) or json
-o, --output Write output to file instead of stdout
--no-recursive Only scan the specified directory, not subdirectories
-V, --vector Scan for specific vector only (1, 2, 3, or 4)
--severity Minimum severity to report: CRITICAL, HIGH, MEDIUM, LOW, INFO

Examples

# Scan project and save report
python commons_text_antipattern_scanner.py ./my-java-app -o report.txt

# JSON output for CI/CD integration
python commons_text_antipattern_scanner.py ./my-java-app --format json -o results.json

# Check only for vulnerable dependency versions (Vector 1)
python commons_text_antipattern_scanner.py ./my-java-app --vector 1

# Show only CRITICAL and HIGH severity findings
python commons_text_antipattern_scanner.py ./my-java-app --severity HIGH

# Scan single directory without recursion
python commons_text_antipattern_scanner.py ./my-java-app/src/main/java --no-recursive

Output

Text Report

================================================================================
APACHE COMMONS TEXT ANTI-PATTERN SCAN RESULTS
CVE-2022-42889 (Text4Shell) / CVE-2025-46295
================================================================================

EXPLOITATION VECTORS REQUIRED:
----------------------------------------
  Vector 1: Vulnerable Dependency (Commons Text 1.5-1.9)
  Vector 2: Dangerous Interpolator (createInterpolator/script/dns/url)
  Vector 3: Untrusted Input (user data to replace())
  Vector 4: No Input Sanitization (missing ${...} filtering)

EXPLOITABILITY ANALYSIS:
----------------------------------------
  Vector 1: [FOUND] (2 findings)
  Vector 2: [FOUND] (3 findings)
  Vector 3: [FOUND] (1 findings)
  Vector 4: [NOT FOUND] (0 findings)

  Missing vectors: 4
  Exploitation requires all 4 vectors to be present.

JSON Output

{
  "summary": {
    "total_findings": 6,
    "files_affected": 3,
    "by_severity": {"CRITICAL": 2, "HIGH": 3, "MEDIUM": 1},
    "by_vector": {"1": 2, "2": 3, "3": 1, "4": 0}
  },
  "exploitability_analysis": {
    "all_vectors_present": false,
    "vectors_found": {"1": true, "2": true, "3": true, "4": false},
    "missing_vectors": [4],
    "assessment": "Potentially exploitable - Missing vectors: [4]"
  },
  "findings": [...]
}

Exit Codes

Code Meaning
0 No critical/high findings
1 Critical or high severity findings detected
2 All exploitation vectors present - likely exploitable

Detection Patterns

Vector 1: Vulnerable Dependency

Scans pom.xml and build.gradle files for:

  • Apache Commons Text versions 1.5, 1.6, 1.7, 1.8, 1.9
  • Maven and Gradle dependency declarations

Vector 2: Dangerous Interpolator

Detects usage of:

  • StringSubstitutor.createInterpolator()
  • ScriptStringLookup (enables RCE)
  • DnsStringLookup (enables DNS exfiltration)
  • UrlStringLookup (enables SSRF)
  • StringLookupFactory usage

Vector 3: Untrusted Input

Identifies data flow patterns where user input reaches replace():

  • HTTP request parameters (@RequestParam, @PathVariable, @RequestBody)
  • Servlet request handling
  • Controller methods
  • File content from uploads
  • Database query results
  • Message queue listeners

Vector 4: No Input Sanitization

Detects absence of:

  • Pattern validation for ${...} syntax
  • Input sanitization/escaping
  • Whitelist filtering

Remediation

Upgrade (Recommended)

Upgrade to Apache Commons Text 1.10.0 or later:

Maven (pom.xml):

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-text</artifactId>
    <version>1.12.0</version>
</dependency>

Gradle (build.gradle):

implementation 'org.apache.commons:commons-text:1.12.0'

Input Validation (If Upgrade Not Possible)

Reject input containing interpolation syntax:

private static final Pattern DANGEROUS_PATTERN = Pattern.compile("\\$\\{[^}]+\\}");

public String safeProcess(String input) {
    if (DANGEROUS_PATTERN.matcher(input).find()) {
        throw new SecurityException("Invalid input: interpolation syntax not allowed");
    }
    return substitutor.replace(input);
}

Disable Dangerous Lookups

Use a custom StringSubstitutor without dangerous lookups:

// Safe: Only use environment and system property lookups
Map<String, StringLookup> lookups = new HashMap<>();
lookups.put("env", StringLookupFactory.INSTANCE.environmentVariableStringLookup());
lookups.put("sys", StringLookupFactory.INSTANCE.systemPropertyStringLookup());

StringLookup safeLookup = StringLookupFactory.INSTANCE.interpolatorStringLookup(lookups, null, false);
StringSubstitutor substitutor = new StringSubstitutor(safeLookup);

CI/CD Integration

GitHub Actions

- name: Scan for Commons Text vulnerabilities
  run: |
    python commons_text_antipattern_scanner.py ./src --format json -o scan-results.json
    if [ $? -eq 2 ]; then
      echo "CRITICAL: All exploitation vectors detected!"
      exit 1
    fi

Jenkins Pipeline

stage('Security Scan') {
    steps {
        sh 'python commons_text_antipattern_scanner.py ./src -o commons-text-report.txt'
    }
    post {
        always {
            archiveArtifacts artifacts: 'commons-text-report.txt'
        }
    }
}

Limitations

  • Static analysis only - does not execute code or trace runtime data flow
  • May produce false positives for variable names matching patterns
  • Cannot detect vulnerabilities in compiled JAR dependencies
  • Multiline pattern matching is heuristic-based

Files Scanned

File Type Extensions/Names
Java source .java
Maven pom.xml
Gradle build.gradle, build.gradle.kts
XML config .xml

License

GNU General Public License v3.0 (GPL-3.0)

Copyright (C) 2025 Garland Glessner <gglessner@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Author

Garland Glessner (gglessner@gmail.com)

See Also

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages